#include <gtest/gtest.h>
#include <fstream>
#include <thread>
#include <chrono>
#include <atomic>
#include <condition_variable>

// GStreamer headers
#include <glib.h>
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <gst/app/gstappsink.h>

// Project headers
#include "utils_log.h"
#include "utils_init.h"
#include "utils_file_ex.h"
#include "common_init.h"
#include "nlohmann/json.hpp"
#include "media_stream.h"

namespace El {
namespace Media {
namespace Test {

class AudioConverter {
public:
    AudioConverter() : pipeline_(nullptr), appsrc_(nullptr), appsink_(nullptr)
    {
        gst_init(nullptr, nullptr);

        // 修改pipeline只解码到PCM
        const char *pipeline_str =
            "appsrc name=audio_src ! "
            "aacparse ! avdec_aac ! "
            "audioresample ! audioconvert ! "
            "audio/x-raw,format=S16LE,rate=48000,channels=2 ! "
            "appsink name=audio_sink";

        GError *error = nullptr;
        pipeline_ = gst_parse_launch(pipeline_str, &error);
        if (!pipeline_) {
            EL_ERROR("Failed to create pipeline: {}", error->message);
            g_error_free(error);
            return;
        }

        appsrc_ = GST_APP_SRC(gst_bin_get_by_name(GST_BIN(pipeline_), "audio_src"));
        appsink_ = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(pipeline_), "audio_sink"));

        if (!appsrc_ || !appsink_) {
            EL_ERROR("Failed to get appsrc or appsink elements");
            return;
        }

        // 设置appsink属性
        g_object_set(G_OBJECT(appsink_), "emit-signals", TRUE, "sync", FALSE, nullptr);

        EL_INFO("Connecting new-sample signal");
        g_signal_connect(appsink_, "new-sample", G_CALLBACK(OnNewSampleStatic), this);

        // 设置AAC输入格式
        GstCaps *caps = gst_caps_new_simple("audio/mpeg", 
            "mpegversion", G_TYPE_INT, 4,
            "stream-format", G_TYPE_STRING, "adts",
            nullptr);
        gst_app_src_set_caps(appsrc_, caps);
        gst_caps_unref(caps);

        // 简单配置,关闭同步
        g_object_set(G_OBJECT(appsrc_), "block", FALSE, nullptr);

        gst_element_set_state(pipeline_, GST_STATE_PLAYING);
    }

    ~AudioConverter()
    {
        // 先停止pipeline
        if (pipeline_) {
            gst_element_set_state(pipeline_, GST_STATE_NULL);
            // 等待pipeline完全停止
            gst_element_get_state(pipeline_, nullptr, nullptr, GST_CLOCK_TIME_NONE);
        }

        // 按照创建的相反顺序释放对象
        if (appsink_) {
            gst_object_unref(appsink_);
            appsink_ = nullptr;
        }
        if (appsrc_) {
            gst_object_unref(appsrc_);
            appsrc_ = nullptr;
        }
        if (pipeline_) {
            gst_object_unref(pipeline_);
            pipeline_ = nullptr;
        }

        EL_INFO("AudioConverter destroyed");
    }

    void PushData(const uint8_t *data, size_t length)
    {
        if (!appsrc_ || !pipeline_)
            return;

        GstBuffer *buffer = gst_buffer_new_allocate(nullptr, length, nullptr);
        if (!buffer) {
            EL_ERROR("Failed to allocate buffer");
            return;
        }

        gst_buffer_fill(buffer, 0, data, length);
        GstFlowReturn ret;
        g_signal_emit_by_name(appsrc_, "push-buffer", buffer, &ret);
        if (ret != GST_FLOW_OK) {
            EL_ERROR("Failed to push buffer, ret: {}", ret);
        }
        gst_buffer_unref(buffer);
    }

private:
    static GstFlowReturn OnNewSampleStatic(GstAppSink *sink, gpointer user_data)
    {
        (void)sink;
        auto *converter = static_cast<AudioConverter *>(user_data);
        return converter->OnNewSample();
    }

    GstFlowReturn OnNewSample()
    {
        GstSample *sample = gst_app_sink_pull_sample(appsink_);
        if (!sample)
            return GST_FLOW_ERROR;

        GstBuffer *buffer = gst_sample_get_buffer(sample);
        GstMapInfo map;

        if (gst_buffer_map(buffer, &map, GST_MAP_READ)) {
            try {
                if (map.size > 0) {
                    std::vector<uint8_t> data(map.data, map.data + map.size);
                    if (!Utils::SaveBufferToFile("/mnt/udisk/audio.pcm", data, false)) {
                        EL_ERROR("Failed to save PCM data");
                    } else {
                        EL_INFO("Saved {} bytes of PCM data", map.size);
                    }
                }
            } catch (const std::exception &e) {
                EL_ERROR("Exception while saving file: {}", e.what());
            }
            gst_buffer_unmap(buffer, &map);
        }

        gst_sample_unref(sample);
        return GST_FLOW_OK;
    }

    GstElement *pipeline_;
    GstAppSrc *appsrc_;
    GstAppSink *appsink_;
};

class AudioConverterTest : public ::testing::Test {
public:
    void OnStream(const MediaFramePtr &ptr)
    {
        if (!ptr) {
            EL_ERROR("Received null frame");
            return;
        }

        if (ptr->GetFrameType() == MEDIA_FRAME_AAC) {
            if (converter_) {
                converter_->PushData(ptr->GetBuffer(), ptr->GetLength());
            } else {
                EL_ERROR("Failed to create audio converter");
            }
        }
    }

protected:
    static void SetUpTestSuite()
    {
        // 初始化基础库
        nlohmann::json config;
        config["log_file"] = "app.log";
        El::Utils::base_init(config);

        // 初始化配置
        config.clear();
        config["general"] = "/app/config/config";
        config["default"] = "/app/config/default";
        config["product"] = "/app/config/product";
        El::Common::common_init(config);
    }

    void SetUp() override {}

    void TearDown() override {}

protected:
    std::unique_ptr<AudioConverter> converter_;
    int32_t stream_handle_{-1};
};

TEST_F(AudioConverterTest, TestAudioConversion)
{
    converter_ = std::make_unique<AudioConverter>();
    if (!converter_) {
        EL_ERROR("Failed to create audio converter");
        return;
    }

    // 获取音频流
    auto stream = Media::StreamSource::Create(0, 0);

    // 启动音频流

    stream_handle_ = stream->Register(std::bind(&AudioConverterTest::OnStream, this, std::placeholders::_1));
    if (stream_handle_ < 0) {
        EL_ERROR("Failed to start audio stream");
        return;
    }
    stream->Start();
    // 等待接收到音频帧
    std::this_thread::sleep_for(std::chrono::seconds(20));

    // 停止音频流
    stream->Stop();
    converter_.reset();
}

} // namespace Test
} // namespace Media
} // namespace El
